import java.io.*;

public class Lexer
{

	public Lexer(){
	
	}
	
	public static StringBuffer lexer(data dat)
	{
		
		String[] KEYWORD = { "INPUT", "OUTPUT", "GOTO", "IF"};
		//these are the keywords used in this language
		
		//String[] OPERATOR = {"+","-","/","*", "%", "!","&","++","--","+=","-=","/=","*=","%="};
		//String[] PUNCTUATOR = {";",":","{","}","(",")",","};
		
		int current=0;			// stores current character to be read from the file as token 
		
		int flag=0;			//used as temporary variable
		
		int flag2=0;			//used as temporary variable
		
		long start=0L;			//stores the starting position of the token for future referencing	
		
		String temp;			//used as temporary for cross-checking in for keywords
		
		StringBuffer arr;		//stores the token value to be returned
		
            	try{             
			
			
			File fl = new File(dat.filename.toString());   			//opens file for compiling                
			
			RandomAccessFile raf =new RandomAccessFile(fl,"rw");		//raf is the file stream
			
			try{raf.seek(dat.last);}catch(Exception e){}			//this goes to the point where token returned dat.last time
			
			try{current=raf.read();}catch(Exception e){}			
				
                	while (current != -1)						//loops uptil file has ended
			{
					flag2=0;
                  	  		if((current == ' ')||(current=='\n')||(current=='\t')||(current=='\r'))
					{
						
						//System.out.println("this is a enter space tab returncarriage"+(char)current);
						//it doesnt count endline or carriage return as token 
						if(current =='\n')
						dat.line_no++;
						try{current = raf.read();}catch(Exception e){}
					}
					else
					{	if(((current>='0')&&(current<='9'))||(current=='.'))
						{				
							//System.out.println("this is 0-9"+(char)current);
							
							if(current == '.')
							flag2=1;
							try{start = raf.getFilePointer();}catch(Exception e){}
							raf.seek(start);
							
							/*
							Here it checks for presencee of two decimal points in a floating number
							is one decimal point is found then flag2 is made 1
							
							the start to dat.last including both contains the constant
							
							*/
							
							dat.last = start;
							try{current = raf.read();}catch(Exception e){}
							while((( current>='0')&&(current<='9'))||(current == '.'))
							{
								//System.out.println("this is 0-9"+(char)current);
								
								if(current == '.')
							{
								if(flag2==1)
								{
									if(current == '.')
									System.out.println("The floating point value is absurd in line "+dat.line_no);
								}
								else
								{
									flag2 =1;
								}
							}
								try{dat.last = raf.getFilePointer();}catch(Exception e){}
								raf.seek(dat.last);
								try{current = raf.read();}catch(Exception e){}
							}
							
							arr = new StringBuffer();
							raf.seek(start-1);
							for(int m=0;m<=(dat.last-start);m++)
							{
								arr.append((char)raf.read());
							}
							
							raf.seek(dat.last);
							dat.code=1;
							/*
							code is used to identify the type if token
							1 = numeric constant
							2= keyword
							3= identifier
							4 = operator
							5 = equal to
							6 = semicolon, curly brace or round bracket or colon
							7 = error in token
							
							*/

							return (arr);
							
						}			
						else
						{	if(((current>='A')&&(current<='Z'))||((current>='a')&&(current<='z')))
							{
								//System.out.println("this is a-z A-A"+(char)current);
								
								try{start = raf.getFilePointer();}catch(Exception e){}
								dat.last = start;
								raf.seek(start);
								try{current = raf.read();}catch(Exception e){}
								while(((current =='_')|| (((current>='A')&&(current<='Z'))||((current>='a')&&(current<='z'))))||((current>='0')&&(current<='9'))||(current=='.'))
								{
									
									
									try{dat.last = raf.getFilePointer();}catch(Exception e){}
									raf.seek(dat.last);
									try{current= raf.read();}catch(Exception e){}
								}
								
								
								
								// Now it checks for being keyword in the keyword list
								
								
								arr = new StringBuffer();
								raf.seek(start-1);
								for(int m=0;m<=(dat.last-start);m++)
								{
									arr.append((char)raf.read());
								}
							
								raf.seek(dat.last);
								temp= arr.toString();
								flag=0;
								for(int k=0;((k<KEYWORD.length)&&(flag==0));k++)
								{
									if(KEYWORD[k].equalsIgnoreCase(temp))
									{
										//System.out.println("KEYWORD\t\t"+start+"\t"+dat.last+"\t"+dat.line_no+"\t"+temp);
										flag=1;
										dat.code=2;
									}
								}
								if(flag==0)
								dat.code=3;
								//System.out.println("IDENTIFIER\t"+start+"\t"+dat.last+"\t"+dat.line_no+"\t"+arr);
								return(arr);
							}
							else
							{	if((current=='+')||(current=='-')||(current=='/')||(current=='*')||(current=='%')||(current=='?')||(current == '>')||(current == '<')||(current =='!'))
								{	//System.out.println("this is + - * / operator "+(char)current);
									
									try{start = raf.getFilePointer();}catch(Exception e){}
									dat.last =start;
									raf.seek(dat.last);
									try{current = raf.read();}catch(Exception e){}
									if(current=='=')
									{
										try{dat.last = raf.getFilePointer();}catch(Exception e){}
										raf.seek(dat.last);
										//this part checks for ==, !=, >=,<= containing two operators 
									}
									else
									{
										//dat.last is the end pointer, ie, operator is single
									}
									arr = new StringBuffer();
									raf.seek(start-1);
									for(int m=0;m<=(dat.last-start);m++)
									{
										arr.append((char)raf.read());
									}
							
									raf.seek(dat.last);
									dat.code=4;
									return(arr);
									//System.out.println("OPERATOR\t"+start+"\t"+dat.last+"\t"+dat.line_no+"\t"+arr);
								}	
								else
								{	if(current == '=')
									{
										try{start = raf.getFilePointer();}catch(Exception e){}
										dat.last = start;
										raf.seek(start);
										try{current = raf.read();}catch(Exception e){}
										//this is a punctuator
										arr = new StringBuffer();
										raf.seek(start-1);
										for(int m=0;m<=(dat.last-start);m++)
										{
											arr.append((char)raf.read());
										}
										raf.seek(dat.last);
										
										dat.code=5;
										return(arr);
									}
									else
								
									{	if((current==';')||(current==':')||(current=='{')||(current=='}') ||(current=='(')||(current==')')||(current=='"'))
										{
										
											
											try{start = raf.getFilePointer();}catch(Exception e){}
											dat.last = start;
											raf.seek(start);
											//punctuators
											try{current = raf.read();}catch(Exception e){}
											//this is a punctuator
											arr = new StringBuffer();
											raf.seek(start-1);
											for(int m=0;m<=(dat.last-start);m++)
											{
												arr.append((char)raf.read());
											}
											raf.seek(dat.last);
											//System.out.println("PUNCTUATOR\t"+start+"\t"+dat.last+"\t"+dat.line_no+"\t"+arr);
											dat.code=6;
											return(arr);
										}
										else
										{	
										
										/*
										
										This checks for special character seqquence like \n , \\ etc
										
										*/
											if(current=='\\')
											{
												try{start = raf.getFilePointer();}catch(Exception e){}
												dat.last = start;
												raf.seek(start);
												
												try{current = raf.read();}catch(Exception e){}
												
												arr = new StringBuffer();
												raf.seek(start-1);
												for(int m=0;m<=(dat.last-start);m++)
												{
													arr.append((char)raf.read());
												}
												raf.seek(dat.last);
												//System.out.println("PUNCTUATOR\t"+start+"\t"+dat.last+"\t"+dat.line_no+"\t"+arr);	
												dat.code=8;
												return(arr);
											}
											else
											{
												
												dat.last= raf.getFilePointer();
												current = raf.read();
												
												arr = new StringBuffer();
												try{arr.append("error");}catch(Exception e){}
												dat.code=7;
												return (arr);
											}
										}
									}
								}
							}
						}
					}
				}
				try{raf.close();}catch(Exception e){}
				arr = new StringBuffer();
				
				/*
					If the file contains no more character then this function returns # which terminates 
					the program in the main function
				*/
				
				arr.append("#");
				return(arr);
			}catch (Exception e)
				{
					System.err.println("File opening error- the file doesnot exist");
					arr = new StringBuffer();
					arr.append("#");
					return(arr);
				}
	}
}
